home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / viewers / polyview / polyvw31.lha / Polyview3.1 / new / playaiff.c < prev    next >
C/C++ Source or Header  |  1993-06-23  |  22KB  |  786 lines

  1. /* ------------------------------------------------------------------------ */
  2. /* THIS IS NOT NCSA-DEVELOPED SOFTWARE.                                     */
  3. /* This file is based on /usr/people/4Dgifts/examples/libaudio/playaiff.c   */
  4. /* as shipped with Silicon Graphics IRIX 4.0.2.                             */
  5. /* ------------------------------------------------------------------------ */
  6.  
  7. /* $Header: /usr3/people/gbourhis/pv3/new/RCS/playaiff.c,v 1.1 92/09/18 10:55:26 marca Exp $ */
  8.  
  9. #ifdef RCSLOG
  10. $Log:    playaiff.c,v $
  11.  * Revision 1.1  92/09/18  10:55:26  marca
  12.  * Initial revision
  13.  * 
  14. #endif
  15.  
  16. #include <stdio.h>
  17. #include <fcntl.h>
  18. #include <errno.h>
  19. #include <sys/types.h>
  20. #include <malloc.h>
  21. #include "aiff.h"
  22. #include <audio.h>
  23.  
  24. /*
  25.  * we're going to nail down the value of infinity for the IEEE conversion
  26.  * routine below: math.h yields to local definition of HUGE_VAL
  27.  */
  28. union 
  29. {
  30.     unsigned long n[2];   /* initialized in main */
  31.     double        d;
  32. } _inf_union;
  33. #define HUGE_VAL _inf_union.d;
  34. #include <math.h>
  35.  
  36. typedef union 
  37. {
  38.     unsigned char b[2];
  39.     short         s;
  40. } align_short_t;
  41.  
  42. typedef union 
  43. {
  44.     unsigned char b[4];
  45.     long         l;
  46. } align_long_t;
  47.  
  48. /*
  49.  * local subroutines
  50.  */
  51. static void   playfile(void);
  52. static void   parse_cmd_line(int argc, char **argv);
  53. static int    read_chunk_header(chunk_header_t *);
  54. static void   read_form_chunk(chunk_header_t *, form_chunk_t *);
  55. static void   read_comm_chunk(chunk_header_t *,comm_chunk_t *, 
  56.                       audio_params_t *audio_params);
  57. static void   init_audio(audio_params_t *, ALport *);
  58. static void   read_ssnd_chunk(chunk_header_t *, ssnd_chunk_t *);
  59. static void   play_audio_samps(comm_chunk_t *,
  60.                                ssnd_chunk_t *, audio_params_t *, ALport);
  61. static void   skip_chunk(chunk_header_t *);
  62. static double ConvertFromIeeeExtended(char *);
  63.  
  64. /*
  65.  * globals 
  66.  */
  67. static char *filename;         /* input file name */
  68. static int fd;            /* input file descriptor */
  69. static char *myname;           /* name of this program */
  70. static int verbose;            /* global flag */
  71. static int bytes_per_samp;    /* sample width */
  72. static int samps_per_frame;    /* frame size */
  73. static int frames_per_sec;    /* sample rate */
  74. static int bytes_per_buf;          /* bytes per sample buffer */
  75. static int samps_per_buf;          /* samples per sample buffer */
  76. static int frames_per_buf;         /* frames per sample buffer */
  77. static double secs_per_frame;   /* time it takes to play one audio frame */
  78. static double secs_per_buf;     /* time it takes to play one sample buffer */
  79. static char *sampbuf;              /* the sample buffer */
  80.  
  81.  
  82. /* Return a 1 if we can play sound, 0 otherwise. */
  83. int InitSound (void)
  84. {
  85.   int n;
  86.  
  87.   /* Assign name for error reports. */
  88.   myname = "PlayAFile";
  89.  
  90.   /*
  91.    * initialize the inifinity union
  92.    */ 
  93.   _inf_union.n[0] = 0x7ff00000;
  94.   _inf_union.n[1] = 0x00000000;  
  95.   
  96.   /*
  97.    * return gracefully if we're running on anything besides a
  98.    * 4D/35 or an Indigo
  99.    */
  100.   if ((n = open("/dev/hdsp/hdsp0master", O_RDWR)) < 0)
  101.     return 0;
  102.   close(n);
  103.   return 1;
  104. }
  105.  
  106. /* Given a filename, just try to open and play the file. */
  107. void PlayAFile (char *fname)
  108. {
  109.   /* Assign input filename to global variable. */
  110.   filename = fname;
  111.  
  112.   /* Open and play the file. */
  113.   if ((fd = open(filename, O_RDONLY)) < 0)
  114.     return;
  115.   playfile();
  116.   close(fd);
  117.  
  118.   return;
  119. }
  120.  
  121.  
  122. /*
  123.  * P L A Y F I L E
  124.  */
  125. static void
  126. playfile(void)
  127. {
  128.     int i,n;
  129.     char buf[8];
  130.     chunk_header_t chunk_header;
  131.     form_chunk_t form_data;
  132.     comm_chunk_t comm_data;
  133.     ssnd_chunk_t ssnd_data;
  134.     audio_params_t audio_params;
  135.     ALport audio_port;
  136.  
  137.     if ((n = read_chunk_header(&chunk_header)) != CHUNK_HEADER)
  138.     {
  139.         fprintf(stderr, "%s: failed to read FORM chunk header\n", myname);
  140.         exit(1);
  141.     }
  142.     if (strncmp(chunk_header.id, "FORM", 4))        /* form container */
  143.     {
  144.         fprintf(stderr, "%s: couldn't find FORM chunk id\n", myname);
  145.         exit(1);
  146.     }
  147.  
  148.     read_form_chunk(&chunk_header, &form_data);
  149.  
  150.     /*
  151.      * loop on the local chunks
  152.      */
  153.     while ((n = read_chunk_header(&chunk_header)) != 0)
  154.     {
  155.         if (n != CHUNK_HEADER)
  156.         {
  157.             fprintf(stderr, "%s: failed to read a chunk header\n", myname);
  158.             exit(1);
  159.         }
  160.  
  161.         if (!strncmp(chunk_header.id, "COMM", 4))    /* common */
  162.         {
  163.             read_comm_chunk(&chunk_header, &comm_data, &audio_params);
  164.         }
  165.         else if (!strncmp(chunk_header.id, "SSND", 4))  /* sound data */
  166.         {
  167.             read_ssnd_chunk(&chunk_header, &ssnd_data);
  168.         }
  169.         else if ((!strncmp(chunk_header.id, "MARK", 4))  /* marker */
  170.               || (!strncmp(chunk_header.id, "INST", 4))  /* instrument */
  171.               || (!strncmp(chunk_header.id, "APPL", 4))   /* appl specific */
  172.               || (!strncmp(chunk_header.id, "MIDI", 4))  /* midi data */
  173.               || (!strncmp(chunk_header.id, "AESD", 4))   /* audio  rec */
  174.               || (!strncmp(chunk_header.id, "COMT", 4))   /* comments */
  175.               || (!strncmp(chunk_header.id, "NAME", 4))   /* text */
  176.               || (!strncmp(chunk_header.id, "AUTH", 4))   /* text */
  177.               || (!strncmp(chunk_header.id, "(c) ", 4))   /* text */
  178.               || (!strncmp(chunk_header.id, "ANNO", 4)))   /* text */
  179.         {
  180.             skip_chunk(&chunk_header);
  181.         }
  182.         else 
  183.         {
  184.             fprintf(stderr,
  185.             "%s: bad chunk id  0x%02x%02x%02x%02x\n",
  186.                      myname, chunk_header.id[0],chunk_header.id[1],
  187.                      chunk_header.id[2], chunk_header.id[3]);
  188.         }
  189.     } /* while */
  190.  
  191.     /*
  192.      * play the sample data
  193.      */
  194.     init_audio(&audio_params, &audio_port);
  195.     play_audio_samps(&comm_data, &ssnd_data, &audio_params, audio_port);
  196.     ALcloseport(audio_port);
  197.     free(sampbuf);
  198. }
  199.  
  200.  
  201. /*
  202.  * R E A D _ C H U N K _ H E A D E R
  203.  */
  204. static int
  205. read_chunk_header(chunk_header_t *chunk_header)
  206. {
  207.     align_long_t align_long;
  208.     char buf[CHUNK_HEADER];
  209.     int i;
  210.     int n;
  211.  
  212.     if ((n = read(fd, buf, CHUNK_HEADER)) != CHUNK_HEADER)
  213.     {
  214.         return(n);
  215.     }
  216.  
  217.     for (i=0; i<4; i++)
  218.     {
  219.         chunk_header->id[i] = buf[i];
  220.     }
  221.     for (i=0; i<4; i++)
  222.     {
  223.         align_long.b[i] = buf[i+4];
  224.     } 
  225.     chunk_header->size = align_long.l;
  226.  
  227.     return(CHUNK_HEADER);
  228. }
  229.  
  230. static void
  231. read_form_chunk(chunk_header_t *chunk_header, form_chunk_t *form_data)
  232. {
  233.     int n;
  234.     char buf[FORM_CHUNK_DATA];
  235.  
  236.     if (chunk_header->size < 0)
  237.     {
  238.         fprintf(stderr, "%s: invalid FORM chunk data size %d\n",myname,
  239.                                  chunk_header->size);
  240.         exit(1);
  241.     }
  242.     else if (chunk_header->size == 0)
  243.     {
  244.         fprintf(stderr,"%s: FORM chunk data size = 0\n", myname);
  245.         exit(0);
  246.     } 
  247.     else
  248.     {
  249.         if (verbose)
  250.         { 
  251.             fprintf(stderr,"%s: FORM chunk data size = %d\n",myname,
  252.                           chunk_header->size);
  253.         }
  254.     }
  255.     if ((n = read(fd, buf, FORM_CHUNK_DATA)) != FORM_CHUNK_DATA) 
  256.     {
  257.         fprintf(stderr, "%s: couldn't read AIFF identifier from %s\n",
  258.                            myname, filename);
  259.         exit(1);
  260.     }
  261.     if (strncmp(buf, "AIFF", 4))
  262.     {
  263.        fprintf(stderr, "%s: %s does not have an AIFF identifier\n",
  264.                   myname, filename);
  265.        exit(1);
  266.     }
  267.     else
  268.     {
  269.         if (verbose)
  270.         {
  271.            fprintf(stderr,"%s: AIFF id\n", myname);
  272.         }
  273.     }
  274. }
  275.  
  276.  
  277. /*
  278.  * R E A D _ C O M M _ C H U N K
  279.  */
  280. static void
  281. read_comm_chunk(chunk_header_t *chunk_header, 
  282.                     comm_chunk_t *comm_data,
  283.                     audio_params_t *audio_params)
  284. {
  285.     int n;
  286.     char *buf, *bufp;
  287.     int i;
  288.     align_short_t align_short;
  289.     align_long_t  align_long;
  290.     double tmpdouble;
  291.  
  292.     buf = malloc(COMM_CHUNK_DATA + 1); /* leave an extra loc at the end */
  293.  
  294.     if ((n = read(fd,  buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA)
  295.     {
  296.         fprintf(stderr, 
  297.         "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
  298.             myname, COMM_CHUNK_DATA, n); 
  299.         exit(1);
  300.     }
  301.     bufp = buf;
  302.     for (i=0; i<2; i++)
  303.     {
  304.        align_short.b[i] = *bufp++;
  305.     }
  306.     comm_data->nchannels = align_short.s;
  307.     for (i=0; i<4; i++) 
  308.     { 
  309.        align_long.b[i]  = *bufp++;
  310.     }
  311.     comm_data->nsampframes = align_long.l;
  312.     for (i=0; i<2; i++)
  313.     {
  314.        align_short.b[i] = *bufp++;
  315.     }
  316.     comm_data->sampwidth = align_short.s; 
  317.  
  318.     /*
  319.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  320.      * floating point number:
  321.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  322.      *
  323.      */
  324.     tmpdouble = ConvertFromIeeeExtended(bufp);
  325.     bufp+=10;
  326.     if (verbose)
  327.     {
  328.         fprintf(stderr,"%s: converted ieee extended rate value to %f\n", 
  329.                                  myname, tmpdouble);
  330.     }
  331.     comm_data->samprate = (long)tmpdouble;
  332.  
  333.     if (verbose)
  334.     {
  335.         fprintf(stderr,"%s: COMM chunk data    num channels = %d\n", myname,
  336.                                          comm_data->nchannels);
  337.         fprintf(stderr,"%s: COMM chunk data    num sample frames = %d\n", 
  338.                                          myname,
  339.                                          comm_data->nsampframes);
  340.         fprintf(stderr,"%s: COMM chunk data    sample size = %d\n", myname, 
  341.                                          comm_data->sampwidth);
  342.         fprintf(stderr,"%s: COMM chunk data    sample rate = %d\n", myname,
  343.                                          comm_data->samprate);
  344.     }
  345.     switch (comm_data->samprate)
  346.     {
  347.         case 48000:
  348.         audio_params->samprate = AL_RATE_48000;        
  349.         break;
  350.     case 44100:
  351.         audio_params->samprate = AL_RATE_44100;
  352.         break;
  353.     case 32000:
  354.         audio_params->samprate = AL_RATE_32000;
  355.         break;
  356.     case 22050:
  357.         audio_params->samprate = AL_RATE_22050;
  358.         break;
  359.     case 16000:
  360.         audio_params->samprate = AL_RATE_16000;
  361.         break;
  362.     case 11025:
  363.         audio_params->samprate = AL_RATE_11025;
  364.         break;
  365.     case  8000:
  366.         audio_params->samprate = AL_RATE_8000;
  367.         break;
  368.         default:
  369.                 fprintf(stderr,"%s: can't set output sample rate to %d\n",
  370.                             myname, comm_data->samprate);
  371.         audio_params->samprate = AL_RATE_48000;        
  372.     }
  373.  
  374.     switch (comm_data->nchannels)
  375.     {
  376.     case 1:
  377.         audio_params->nchannels = AL_MONO;
  378.         break;
  379.     case 2:
  380.         audio_params->nchannels = AL_STEREO;
  381.         break;
  382.     default:
  383.         fprintf(stderr, "%s: can't handle %d channels per frame\n",
  384.                     myname, comm_data->nchannels);
  385.         audio_params->nchannels = AL_STEREO;
  386.     }
  387.     switch (comm_data->sampwidth)
  388.     {
  389.     case 8:
  390.          audio_params->sampwidth = AL_SAMPLE_8;
  391.         break;
  392.     case 16:
  393.          audio_params->sampwidth = AL_SAMPLE_16;
  394.         break;
  395.     case 24:
  396.          audio_params->sampwidth = AL_SAMPLE_24;
  397.         break;
  398.     default:
  399.         fprintf(stderr, "%s: unsupported sample width %d bits\n",
  400.             myname, comm_data->nchannels);
  401.          audio_params->sampwidth = AL_SAMPLE_16;
  402.     }
  403.     free(buf);
  404. }
  405.  
  406. /*
  407.  * I N I T _ A U D I O
  408.  */
  409. static void
  410. init_audio(audio_params_t *audio_params, ALport *audio_port)
  411. {
  412.     ALconfig audio_port_config;
  413.     long pvbuf[2];
  414.     long buflen;
  415.  
  416.     /*
  417.      * set output sample rate
  418.      */
  419.     pvbuf[0] = AL_OUTPUT_RATE;
  420.     pvbuf[1] = audio_params->samprate;
  421.     buflen   = 2;
  422.     ALsetparams(AL_DEFAULT_DEVICE, pvbuf, buflen);
  423.  
  424.     /*
  425.      * decide what size blocks of samples we should read from the
  426.      * AIFF file and pass to ALwritesamps
  427.      */
  428.     switch (audio_params->sampwidth)
  429.     {
  430.         case AL_SAMPLE_8: bytes_per_samp = 1; break;
  431.  
  432.         default:
  433.         case AL_SAMPLE_16: bytes_per_samp = 2; break;
  434.     }
  435.     switch (audio_params->nchannels)
  436.     {
  437.         case AL_MONO: samps_per_frame = 1; break;
  438.       
  439.         default:
  440.         case AL_STEREO: samps_per_frame = 2; break;
  441.     }
  442.     switch(audio_params->samprate)
  443.       {
  444.       case AL_RATE_48000: frames_per_sec = 48000; break;
  445.       case AL_RATE_44100: frames_per_sec = 44100; break;
  446.       case AL_RATE_32000: frames_per_sec = 32000; break;
  447.       case AL_RATE_22050: frames_per_sec = 22050; break;
  448.       case AL_RATE_16000: frames_per_sec = 16000; break;
  449.       case AL_RATE_11025: frames_per_sec = 11025; break;
  450.       case AL_RATE_8000:  frames_per_sec =  8000; break;
  451.       }
  452.     
  453.     if (frames_per_sec % 2 == 0)
  454.     {
  455.        /*
  456.         * make the buffer large enough to hold 1/2 sec of audio frames
  457.         */
  458.        secs_per_frame = 1.0 / ((double)frames_per_sec);
  459.        bytes_per_buf  = bytes_per_samp * samps_per_frame * frames_per_sec / 2;
  460.        samps_per_buf  = bytes_per_buf / bytes_per_samp;
  461.        frames_per_buf = samps_per_buf / samps_per_frame;
  462.        secs_per_buf   = secs_per_frame * frames_per_buf;
  463.        sampbuf = malloc(bytes_per_buf); 
  464.     }
  465.     else /* eg, can't divide 11025 by 2 to get exactly 0.5 sec of samples */
  466.     {
  467.        secs_per_frame = 1.0 / ((double)frames_per_sec);
  468.        bytes_per_buf  = bytes_per_samp * samps_per_frame*(frames_per_sec+1)/2;
  469.        samps_per_buf  = bytes_per_buf / bytes_per_samp;
  470.        frames_per_buf = samps_per_buf / samps_per_frame;
  471.        secs_per_buf   = secs_per_frame * frames_per_buf;
  472.        sampbuf = malloc(bytes_per_buf); 
  473.     }
  474.  
  475.  
  476.     /*
  477.      * configure and open audio port
  478.      */
  479.     audio_port_config = ALnewconfig();
  480.     ALsetwidth(audio_port_config, audio_params->sampwidth);
  481.     ALsetchannels(audio_port_config, audio_params->nchannels);
  482.  
  483.     /*
  484.      * make the ring buffer large enough to hold 1 sec of audio samples
  485.      */
  486.     ALsetqueuesize(audio_port_config, samps_per_buf*2);
  487.     *audio_port = ALopenport(myname, "w", audio_port_config);
  488. }
  489.  
  490.  
  491. static void 
  492. read_ssnd_chunk(chunk_header_t *chunk_header, ssnd_chunk_t *ssnd_data)
  493. {
  494.     char buf[SSND_CHUNK_DATA];
  495.     int i;
  496.     align_long_t align_long;
  497.  
  498.     read(fd, buf, SSND_CHUNK_DATA);
  499.  
  500.     for (i=0; i<4; i++)
  501.     {
  502.         align_long.b[i] = buf[i];
  503.     }
  504.     ssnd_data->offset = align_long.l;
  505.     for (i=0; i<4; i++)
  506.     {
  507.         align_long.b[i] = buf[i+4];
  508.     }
  509.     ssnd_data->blocksize = align_long.l;
  510.     if (verbose)
  511.     {
  512.         fprintf(stderr, "%s: SSND data  offset=%d  blocksize=%d\n",
  513.                             myname, ssnd_data->offset, ssnd_data->blocksize);
  514.     }
  515.     /*
  516.      * store the offset to the beginning of the audio sample data so that
  517.      * we can come back and play it later
  518.      */ 
  519.     ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
  520.     ssnd_data->sample_area_bytes = chunk_header->size - 2*sizeof(long);
  521.     if (chunk_header->size %2 == 1)
  522.     {
  523.         if (verbose)
  524.         {  
  525.           fprintf(stderr, 
  526.              "%s: SSND data: odd size %d; assume there's a trailing pad byte\n",
  527.              myname, chunk_header->size);
  528.     
  529.         }
  530.         ssnd_data->sample_area_bytes++;
  531.     }
  532.  
  533.     /*
  534.      * move the fileptr to the end of the chunk
  535.      */
  536.     lseek(fd, ssnd_data->sample_area_bytes, SEEK_CUR);
  537. }
  538.  
  539.  
  540. /*
  541.  * P L A Y _ A U D I O _ S A M P S
  542.  */
  543. static void
  544. play_audio_samps(
  545.                 comm_chunk_t *comm_data,
  546.                 ssnd_chunk_t *ssnd_data, 
  547.                 audio_params_t *audio_params,
  548.                 ALport audio_port)
  549. {
  550.     int num_bufs;
  551.     int leftover_bytes;
  552.     int leftover_samps;
  553.     int leftover_frames;
  554.     int samp_count;
  555.     int frame_count;
  556.     double sec_count;
  557.     int i;
  558.     int bytes_read;
  559.     int samples_read;
  560.     int done;
  561.     int total_frames;    
  562.     int total_samps;
  563.     int total_samp_bytes;
  564.    
  565.     if (verbose)
  566.     {
  567.         fprintf(stderr,
  568.                     "%s: play SSND chunk    sample section = %d bytes\n",
  569.                     myname, ssnd_data->sample_area_bytes);
  570.     }
  571.  
  572.     /*
  573.      * figure out how many reads we have to do
  574.      */
  575.     total_frames     =  comm_data->nsampframes;
  576.     total_samps      =  total_frames * samps_per_frame;
  577.     total_samp_bytes =  total_samps * bytes_per_samp;
  578.     num_bufs         = total_samp_bytes / bytes_per_buf;
  579.     leftover_bytes   = total_samp_bytes % bytes_per_buf;
  580.     leftover_samps   = leftover_bytes / bytes_per_samp;
  581.     leftover_frames  = leftover_samps / samps_per_frame;
  582.  
  583.     if (verbose) 
  584.     {
  585.         fprintf(stderr, 
  586.            "%s: play data: total sample bytes = %d total frames = %d\n",
  587.                     myname, total_samp_bytes, total_frames);
  588.         fprintf(stderr, "%s: play data: %d bytes/blk =%d frames/blk\n",
  589.                     myname, bytes_per_buf, frames_per_buf);
  590.         fprintf(stderr, 
  591.                 "%s: play data:  blocks = %d  leftover samps=%d frames=%d\n",
  592.                 myname, num_bufs, leftover_samps, leftover_frames); 
  593.     }
  594.  
  595.     /*
  596.      * move the fileptr to the beginning of the sample data
  597.      */
  598.     lseek(fd, ssnd_data->file_position, SEEK_SET);
  599.     /*
  600.      * note that there may be some pad bytes following the valid samples -
  601.      * for example, the sample data area may be padded so that the valid 
  602.      * samples begin on a block boundary and the sample area ends on a block
  603.      * boundary (where blocksize is specified by the user)
  604.      */
  605.     done        = 0;
  606.     samp_count  = 0;
  607.     frame_count = 0; 
  608.     sec_count   = 0.0;
  609.     for (i=0; i<num_bufs; i++)
  610.     {
  611.         samp_count  += samps_per_buf;
  612.         frame_count += frames_per_buf;
  613.         sec_count   += secs_per_buf;
  614.  
  615.         if (verbose) 
  616.         {
  617.             fprintf(stderr, "%s: %d sample frames  %6.2f secs\n",
  618.                      myname, frame_count, sec_count); 
  619.         }
  620.         if ((bytes_read = read(fd, sampbuf, bytes_per_buf)) < bytes_per_buf)
  621.         {
  622.             if (verbose)
  623.             {
  624.                 fprintf(stderr, "%s: short read on audio sample data\n", 
  625.                         myname);
  626.             }
  627.             done++;
  628.         }
  629.         samples_read = bytes_read / bytes_per_samp;
  630.         ALwritesamps(audio_port, sampbuf, samples_read);
  631.         if (done)
  632.         {
  633.           /*
  634.            * allow the audio buffer to drain
  635.            */
  636.             while(ALgetfilled(audio_port) > 0)sginap(1);
  637.             return;
  638.         }
  639.     }
  640.     /*
  641.      * play the leftovers
  642.      */
  643.     samp_count  += leftover_samps;
  644.     frame_count += leftover_frames;
  645.     sec_count   += ((double)leftover_frames) * secs_per_frame;
  646.     if (verbose && leftover_samps>0) 
  647.     {
  648.         fprintf(stderr, "%s: %d sample frames  %6.2f secs\n",
  649.                myname, frame_count, sec_count); 
  650.     }
  651.     if ((bytes_read = read(fd, sampbuf, leftover_bytes)) < leftover_bytes)
  652.     {
  653.         if (verbose)
  654.         {
  655.             fprintf(stderr, 
  656.                 "%s: short read: expected %d sample bytes, got %d bytes\n", 
  657.                                  myname, leftover_bytes, bytes_read);
  658.         }
  659.     }
  660.     samples_read = bytes_read / bytes_per_samp;
  661.     ALwritesamps(audio_port, sampbuf, samples_read);
  662.  
  663.     /*
  664.      * allow the audio buffer to drain
  665.      */
  666.     while(ALgetfilled(audio_port) > 0)sginap(1);
  667.     return;
  668. }
  669.  
  670. /*
  671.  * S K I P _ C H U N K
  672.  */
  673. static void
  674. skip_chunk(chunk_header_t *chunk_header)
  675. {
  676.     char id[5];
  677.     int s;
  678.  
  679.     strncpy(id, chunk_header->id, 4);
  680.     id[4] = '\0'; 
  681.  
  682.     if (verbose) 
  683.     {
  684.         fprintf(stderr, "%s: %s chunk   data size = %d bytes   skipped\n",
  685.                              myname, id, chunk_header->size);
  686.     }
  687.     /* skip the pad byte, if necessary */
  688.     s = ((chunk_header->size % 2) == 1) ? chunk_header->size + 1 : chunk_header->size;
  689.     lseek(fd, s, SEEK_CUR);
  690. }
  691.  
  692. /*
  693.  * C O N V E R T   F R O M   I E E E   E X T E N D E D  
  694.  */
  695.  
  696. /* 
  697.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  698.  * All rights reserved.
  699.  *
  700.  * Warranty Information
  701.  *  Even though Apple has reviewed this software, Apple makes no warranty
  702.  *  or representation, either express or implied, with respect to this
  703.  *  software, its quality, accuracy, merchantability, or fitness for a
  704.  *  particular purpose.  As a result, this software is provided "as is,"
  705.  *  and you, its user, are assuming the entire risk as to its quality
  706.  *  and accuracy.
  707.  *
  708.  * This code may be used and freely distributed as long as it includes
  709.  * this copyright notice and the above warranty information.
  710.  
  711.  * Machine-independent I/O routines for IEEE floating-point numbers.
  712.  *
  713.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  714.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  715.  * impossible to preserve NaN's in a machine-independent way.
  716.  * Infinities are, however, preserved on IEEE machines.
  717.  *
  718.  * These routines have been tested on the following machines:
  719.  *    Apple Macintosh, MPW 3.1 C compiler
  720.  *    Apple Macintosh, THINK C compiler
  721.  *    Silicon Graphics IRIS, MIPS compiler
  722.  *    Cray X/MP and Y/MP
  723.  *    Digital Equipment VAX
  724.  *
  725.  *
  726.  * Implemented by Malcolm Slaney and Ken Turkowski.
  727.  *
  728.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  729.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  730.  * floating-point format, and conversions to and from IEEE single-
  731.  * precision floating-point format.
  732.  *
  733.  * In 1991, Ken Turkowski implemented the conversions to and from
  734.  * IEEE double-precision format, added more precision to the extended
  735.  * conversions, and accommodated conversions involving +/- infinity,
  736.  * NaN's, and denormalized numbers.
  737.  */
  738.  
  739. #ifndef HUGE_VAL
  740. # define HUGE_VAL HUGE
  741. #endif /* HUGE_VAL */
  742.  
  743. # define UnsignedToFloat(u)    \
  744.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  745.  
  746. /****************************************************************
  747.  * Extended precision IEEE floating-point conversion routine.
  748.  ****************************************************************/
  749.  
  750. static double
  751. ConvertFromIeeeExtended(char *bytes)
  752. {
  753.     double    f;
  754.     long    expon;
  755.     unsigned long hiMant, loMant;
  756.     
  757.     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
  758.     hiMant    =    ((unsigned long)(bytes[2] & 0xFF) << 24)
  759.             |    ((unsigned long)(bytes[3] & 0xFF) << 16)
  760.             |    ((unsigned long)(bytes[4] & 0xFF) << 8)
  761.             |    ((unsigned long)(bytes[5] & 0xFF));
  762.     loMant    =    ((unsigned long)(bytes[6] & 0xFF) << 24)
  763.             |    ((unsigned long)(bytes[7] & 0xFF) << 16)
  764.             |    ((unsigned long)(bytes[8] & 0xFF) << 8)
  765.             |    ((unsigned long)(bytes[9] & 0xFF));
  766.  
  767.     if (expon == 0 && hiMant == 0 && loMant == 0) {
  768.         f = 0;
  769.     }
  770.     else {
  771.         if (expon == 0x7FFF) {    /* Infinity or NaN */
  772.             f = HUGE_VAL;
  773.         }
  774.         else {
  775.             expon -= 16383;
  776.             f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
  777.             f += ldexp(UnsignedToFloat(loMant), expon-=32);
  778.         }
  779.     }
  780.  
  781.     if (bytes[0] & 0x80)
  782.         return -f;
  783.     else
  784.         return f;
  785. }
  786.